package com.jzo2o.market.task;

import com.jzo2o.api.customer.CommonUserApi;
import com.jzo2o.api.customer.dto.response.CommonUserResDTO;
import com.jzo2o.common.expcetions.BadRequestException;
import com.jzo2o.common.expcetions.DBException;
import com.jzo2o.common.utils.CollUtils;
import com.jzo2o.common.utils.DateUtils;
import com.jzo2o.market.constants.RedisConstants;
import com.jzo2o.market.enums.CouponStatusEnum;
import com.jzo2o.market.model.domain.Activity;
import com.jzo2o.market.model.domain.Coupon;
import com.jzo2o.market.service.IActivityService;
import com.jzo2o.market.service.ICouponService;
import com.jzo2o.redis.model.SyncMessage;
import lombok.extern.slf4j.Slf4j;
import org.redisson.api.RLock;
import org.redisson.api.RedissonClient;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.data.redis.core.Cursor;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.ScanOptions;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;

import java.util.List;
import java.util.Map;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;

/**
 * 同步数据的异步处理类
 *
 * @Author mr.wu
 * @Date 2024-12-20 15:01
 */
@Component
@Slf4j
public class SyncMessageTask {
    @Autowired
    private RedisTemplate redisTemplate;
    @Autowired
    private RedissonClient redissonClient;
    @Autowired
    private ApplicationContext applicationContext;


    /**
     * 批量获取缓存同步数据
     * 将同步数据同步到DB
     * @param index 索引号的值，就是 活动id%10的结果
     * @return
     */
    @Async("taskExecutor")
    public void  batchHandeSyncMessage(Long index){
        //执行任务
        log.info("{}执行任务:{}",Thread.currentThread().getName(),index);
        String redisKey= String.format(RedisConstants.RedisKey.COUPON_SEIZE_SYNC_QUEUE_NAME,index);
        String lockName="LOCK:"+redisKey;
        //基于队列名获取锁实例
        RLock lock = redissonClient.getLock(lockName);
        //尝试获取锁，最多等待3秒，持锁时间为5秒
        List<SyncMessage<Object>> syncMessageList=null;
        try {
            boolean b = lock.tryLock(3, 80, TimeUnit.SECONDS);
            //判断加锁是否失败
            if(!b){
                log.error("{}执行任务,加锁失败",Thread.currentThread().getName());
                return;
            }
             syncMessageList = this.batchGetSyncMessage(redisKey);
        } catch (InterruptedException e) {
            //加锁时发生异常
            e.printStackTrace();
            log.error("{}执行任务,加锁失败",Thread.currentThread().getName());
        }finally {
            //同步数据到数据库
            if(CollUtils.isNotEmpty(syncMessageList)){
                SyncMessageTask owner = applicationContext.getBean(SyncMessageTask.class);
                //更新数据到数据库
                owner.syncMessageToDB(syncMessageList);
                //删除缓存中的同步数据
                List<String> hashkeys = syncMessageList.stream().map(SyncMessage::getKey).collect(Collectors.toList());
                Object[] array = hashkeys.toArray();
                redisTemplate.opsForHash().delete(redisKey,array);
                log.info("同步成功"+redisKey);
            }

            //释放锁
            lock.unlock();
        }
    }
    @Autowired
    private CommonUserApi userApi;
    @Autowired
    private IActivityService activityService;

    @Autowired
    private ICouponService couponService;
    @Transactional(rollbackFor = Exception.class)
    public void syncMessageToDB(List<SyncMessage<Object>> syncMessageList) {
        for (SyncMessage<Object> syncMessage : syncMessageList) {
            //判断用户是否存在
            Long userId = Long.valueOf(syncMessage.getKey());//同步数据的key是用户id
            CommonUserResDTO user = userApi.findById(userId);
            if(user==null){
                throw new BadRequestException("用户不存在");
            }
            //判断活动是否存在
            Long activityId= Long.valueOf(syncMessage.getValue().toString());
            Activity activity = activityService.getById(activityId);
            if(activity==null){
                throw new BadRequestException("活动不存在");
            }
            Coupon coupon = new Coupon();
            //设置用户信息
            coupon.setUserId(userId);
            coupon.setUserName(user.getNickname());
            coupon.setUserPhone(user.getPhone());
            //设置活动信息
            coupon.setActivityId(activityId);
            coupon.setAmountCondition(activity.getAmountCondition());
            coupon.setDiscountAmount(activity.getDiscountAmount());
            coupon.setDiscountRate(activity.getDiscountRate());
            coupon.setType(activity.getType());
            coupon.setName(activity.getName());
            coupon.setValidityTime(DateUtils.now().plusDays(activity.getValidityDays()));//设置过期时间
            //设置优惠卷使用状态
            coupon.setStatus(CouponStatusEnum.NO_USE.getStatus());
            //保存优惠卷到数据库
            boolean save = couponService.save(coupon);
            if(!save){
                throw new DBException("添加领取优惠券记录失败");
            }
            boolean update=activityService.decrStockNum(activityId);
            if(!update){
                throw new DBException("更新库存失败");
            }
        }
    }

    private List<SyncMessage<Object>> batchGetSyncMessage(String redisKey) {
        //一次获取多少条数据
        Cursor<Map.Entry<String,Object>> scan = redisTemplate.opsForHash().scan(redisKey, ScanOptions.scanOptions().count(10).build());
        //如果游标不为空，处理数据，并关闭游标
        if(scan!=null){
            List<SyncMessage<Object>> list = scan.stream().map(x -> SyncMessage.builder().key(x.getKey()).value(x.getValue()).build()).collect(Collectors.toList());
            scan.close();
            return list;
        }
        return null;
    }
}